package com.bot.rf;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.bot.rf.config.LibraryConfig;
import com.bot.rf.config.UserConfig;
import com.bot.rf.entity.BookInfo;
import com.bot.rf.excel.*;
import com.bot.rf.sql.util.LocalSqlUtil;
import com.bot.rf.util.HttpUtil;
import com.bot.rf.util.WebServiceUtil;
import com.bot.rf.util.ZipUtil;

import java.io.*;
import java.nio.file.Paths;
import java.util.*;

import static com.bot.rf.util.MyLogger.LOGGER;
import static com.bot.rf.util.FileUtil.deleteExpiredFile;
import static com.bot.rf.util.FileUtil.deleteFile;
import static com.bot.rf.util.FileUtil.createFile;
import static com.bot.rf.config.LibraryConfig.IS_ONLINE;

/**
 * @program: report-form-demo
 * @description: 报表入口类
 * @author: zyy
 * @create: 2021-02-24 13:48
 **/
public class GenerateReport {

    /**
     * RFID和相机Res文件处理结果
     */
    private static Map<String, BookInfo> rfResBookList;

    private static List<BookExcel> allBookExcels;

    /**
     * RFID和相机Res文件处理完成标志
     */
    private static Boolean rfResFlag = false;
    private static Boolean cvResFlag = false;
    /**
     * 当前报表所属楼层
     **/
    private static String floorNo;

    /**
     * 报表存储路径
     **/
    private static String reportPath;

    /**
     * 异常图书的个数
     */
    private static Integer abnormalBookNums;

    /**
     * 报表生成方法
     */
    public void generateReport(){
        LOGGER.info("开始生成报表...");
        // 初始化数据
        initExcel();
    }

    /**
     * 报表生成
     */
    public void initExcel(){
        ExcelWriter excelWriter = null;
        // map：key sheetName；value bookList
        Map<String, List<BookExcel>> bookExcelMap = new HashMap<>();
        List<AbnormalExcel> abnormalList = new ArrayList<>();
        List<ErrorExcel> errorExcels = new ArrayList<>();
        List<BookExcel> statusExcels = new ArrayList<>();
        allBookExcels = new ArrayList<>();
        Set<String> sheetNameList = new TreeSet<>(Comparator.naturalOrder());
        for (Map.Entry<String, BookInfo> entry : rfResBookList.entrySet()) {
            BookInfo bookInfo = entry.getValue();
            List<BookExcel> bookExcelList;
            // 创建sheetName
            String sheetName = LibraryConfig.getSheetName(bookInfo.getLocation());
            // 层架位置信息
            String shelfIndex = LibraryConfig.getBookShelfIndex(bookInfo.getLocation());
            // 层架位置代码
            String shelfIndexCode = LibraryConfig.getBookShelfIndexCode(bookInfo.getLocation());
            BookExcel bookExcel = new BookExcel(bookInfo, floorNo, sheetName+shelfIndex,shelfIndexCode,"正确");
            // 异常
            if (bookInfo.isAbnormal()) {
                AbnormalExcel abnormalExcel = new AbnormalExcel(bookInfo, floorNo, sheetName+shelfIndex,shelfIndexCode);
                abnormalList.add(abnormalExcel);
                bookExcel.setErrorShelf("");
                bookExcel.setBookStatus("");
                bookExcel.setErrorStatus("");
            }else{
                // 错架
                if(!shelfIndexCode.equals(bookInfo.getTemporaryLocationName())){
                    int rowNo = bookInfo.getLocation().getRowNo();
                    int shelfNo = bookInfo.getLocation().getShelfNo();
                    int layerNo = bookInfo.getLocation().getLayerNo();
                    if (bookInfo.getTemporaryLocationName() == null || "".equals(bookInfo.getTemporaryLocationName())){
                        bookExcel.setErrorShelf("未知");
                    }
                    else if (rowNo == 13 && (shelfNo == 11 || shelfNo == 12) && layerNo == 1){
                        bookExcel.setErrorShelf("错架");
                        ErrorExcel errorExcel = new ErrorExcel(bookInfo,floorNo,shelfIndexCode,sheetName+shelfIndex);
                        errorExcels.add(errorExcel);
                    }
                    else{
                        // 相邻列错不算错架
                        boolean nearError = LibraryConfig.handleErrorShelf(shelfIndexCode,bookInfo.getTemporaryLocationName());
                        boolean sideError = LibraryConfig.handleSideError(shelfIndexCode,bookInfo.getTemporaryLocationName());
                        if (nearError){
                            if (sideError){
                                bookExcel.setErrorShelf("错架");
                                ErrorExcel errorExcel = new ErrorExcel(bookInfo,floorNo,shelfIndexCode,sheetName+shelfIndex);
                                errorExcels.add(errorExcel);
                            }else{
//                                LOGGER.info("ab 对穿错修改：" + bookInfo.getTagId() + " " + shelfIndexCode + " " +bookInfo.getTemporaryLocationName() );
                                // 更新数据库
                                bookExcel.setShelfCode(bookInfo.getTemporaryLocationName());
                                bookExcel.setShelf(LibraryConfig.handleChangeShelf(sheetName+shelfIndex,bookInfo.getTemporaryLocationName()));
                            }
                        }else{
//                            LOGGER.info("隔1 2 列错修改：" + bookInfo.getTagId() + " " + shelfIndexCode + " " +bookInfo.getTemporaryLocationName() );
                            // 更新数据库
                            bookExcel.setShelfCode(bookInfo.getTemporaryLocationName());
                            bookExcel.setShelf(LibraryConfig.handleChangeShelf(sheetName+shelfIndex,bookInfo.getTemporaryLocationName()));
                        }
                    }
                }
                // 馆藏状态错误
                if (!"0".equals(bookInfo.getProcessType())){
                    statusExcels.add(bookExcel);
                }
            }

            // 添加到map中的bookList里
            bookExcelList = bookExcelMap.get(sheetName);
            if (bookExcelList == null) {
                bookExcelList = new ArrayList<>();
            }
            bookExcelList.add(bookExcel);
            bookExcelMap.put(sheetName, bookExcelList);
            sheetNameList.add(sheetName);
        }
        // 排序
        for (List<BookExcel> list : bookExcelMap.values()) {
            Collections.sort(list);
        }
        Collections.sort(abnormalList);
        Collections.sort(errorExcels);
        Collections.sort(statusExcels);
        // 生成Excel
        try {
            // 指定Excel输出文件
            excelWriter = EasyExcel.write(reportPath).build();
            // 生成统计sheet
            WriteSheet totalSheet = EasyExcel.writerSheet(0, "统计信息").head(StatisticExcel.class).build();
            excelWriter.write(getTotalData(abnormalList.size(),errorExcels.size(),statusExcels.size()), totalSheet);
            // 生成异常sheet
            WriteSheet totalTagSheet = EasyExcel.writerSheet(1, "异常图书").head(AbnormalExcel.class).build();
            excelWriter.write(abnormalList, totalTagSheet);
            // 生成错架sheet
            WriteSheet errorSheet = EasyExcel.writerSheet(2, "错架图书").head(ErrorExcel.class).build();
            excelWriter.write(errorExcels, errorSheet);
            // 生成错架sheet
            WriteSheet statusSheet = EasyExcel.writerSheet(3, "馆藏状态错误").head(BookExcel.class).build();
            excelWriter.write(statusExcels, statusSheet);
            // sheet的序号
            int sheetNo = 4;
            for (String sheetName : sheetNameList) {
                // 创建sheet-盘点统计
                WriteSheet bookSheet = EasyExcel.writerSheet(sheetNo, sheetName).head(BookExcel.class).build();
                // 写入sheet
                excelWriter.write(bookExcelMap.get(sheetName), bookSheet);
                sheetNo++;
            }
            LOGGER.info("报表生成！");
        } finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
        LOGGER.info("报表生成！");
    }

    /**
     * 统计数据
     * @return
     */
    public List<StatisticExcel> getTotalData(int abnormalNums,int errorNums,int errorStatusNums) {
        List<StatisticExcel> result = new ArrayList<>();
        StatisticExcel totalExcelModel = new StatisticExcel(rfResBookList.entrySet().size(),
                abnormalNums,errorNums,errorStatusNums);
        result.add(totalExcelModel);
        return result;
    }

    /**
     * 报表生成结束方法
     */
    public void onReportEnd(){
        // 上传文件
        if (UserConfig.UPLOAD_TO_SERVER){
            HttpUtil.UploadFileByHttpClient(reportPath);
        }
        // 发送邮件
        zipSend();
        // 清除Res处理结束标志
        rfResFlag = false;
        // 清除上次Res图书集合
        rfResBookList.clear();
        reportPath = null;
        // 报表结束
        LOGGER.info("创建结束文件");
        createFile(UserConfig.REPORT_END_PATH);
    }

    /**
     * RFID处理Res文件回调函数
     *
     * @param floorNo             当前盘点楼层
     * @param reportPath          报表生成路径
     * @param rfResBookList       RFID读取到的Res中书目
     */
    public static void rfResProcessCallback(String floorNo,
                                            String reportPath,
                                            Map<String, BookInfo> rfResBookList,
                                            Integer abnormalBookNums) {
        GenerateReport.rfResFlag = true;
        GenerateReport.floorNo = floorNo;
        GenerateReport.reportPath = reportPath;
        GenerateReport.rfResBookList = rfResBookList;
        GenerateReport.abnormalBookNums = abnormalBookNums;
    }

    /**
     * RFID的Res文件是否处理结束
     *
     * @return rfResFlag
     */
    public Boolean rfResFinished() {
        return rfResFlag;
    }

    /**
     * 发送邮件
     */
    private void zipSend(){
        LOGGER.info("发送邮件");
        String zipFilePath = reportPath.replaceAll("xlsx", "zip");
        LOGGER.info("zipFilePath: " + zipFilePath);
        List<String> dataPath = new ArrayList<>();
        dataPath.add(zipFilePath);
        try {
            ZipUtil.zip(dataPath,zipFilePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        UserConfig.MAIL.sendEmail(LibraryConfig.LIBRARY_NAME + "，" + floorNo + "，DataSheet",
                "这是此次盘点生成的报表。" +
                        "\r\n盘点楼层：" + floorNo +
                        "\r\nRFID扫描图书数量：" + rfResBookList.entrySet().size() +
                        "\r\n异常图书数量：" + abnormalBookNums, zipFilePath);
        deleteFile(zipFilePath);
    }

    /**
     * 报表程序入口方法
     * @param args
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        LOGGER.info("Version " + "1.0.0");
        LOGGER.info("Update at " + "2021/6/19 10:40");
        LOGGER.info("Updating info " + "初始化项目");
        LOGGER.info("清理过期文件");
        deleteExpiredFile(UserConfig.DESKTOP_PATH + "\\Tooker\\result", 60);
        deleteExpiredFile(UserConfig.DESKTOP_PATH + "\\Tooker\\data", 60);
        deleteExpiredFile(UserConfig.DESKTOP_PATH + "\\Tooker\\log_I&Q", 30);
        deleteExpiredFile(UserConfig.DESKTOP_PATH + "\\Tooker\\Report\\log\\", 30);
        // 调用UserConfig构造方法，初始化Mail类静态变量
        UserConfig userConfig = new UserConfig();
        LOGGER.info("清理上次传输文件夹");
        deleteFile(UserConfig.DESKTOP_PATH + "\\Tooker\\Config_I&Q\\failed_files");
        deleteFile(UserConfig.DESKTOP_PATH + "\\Tooker\\Config_I&Q\\failed_res");
        deleteFile(UserConfig.DESKTOP_PATH + "\\Tooker\\Config_I&Q\\lastdate.f");
        deleteFile(UserConfig.REPORT_END_PATH);

        if (UserConfig.RESET_DATABASE){
            LOGGER.info("重置数据库");
            LocalSqlUtil.delete();
            List<BookInfo> list = WebServiceUtil.updateBookInfoByLocation();
            LOGGER.info("查询 " + list.size() +"条");
            Thread.sleep(500);
            LocalSqlUtil.batchUpdateBookInfo(list);
            LOGGER.info("更新结束");
        }

        //IS_ONLINE = false;
        if (IS_ONLINE){
            // 上线模式
            // 监听RFID文件夹线程
            String rfidResFilePath = UserConfig.DESKTOP_PATH + "\\Tooker\\result";
            File rfidResFolder = new File(rfidResFilePath);
            if (!rfidResFolder.exists()) {
                rfidResFolder.mkdirs();
            }
            new Thread(new WatchFilePath(Paths.get(rfidResFilePath))).start();

            // 报表生成主线程
            GenerateReport report = new GenerateReport();
            while (true){
                Thread.sleep(500);
                // 监听两个Res文件夹处理结束
                boolean resFinished = report.rfResFinished();
                if (resFinished){
                    report.generateReport();
                    report.onReportEnd();
                }
            }
        }else {
            // test模式
            String rfResPath = "C:\\Users\\Dell\\Desktop\\Tooker\\result\\J1_2021-06-24_16-50-44_full.res";
            Res2Database res2Database = new Res2Database(rfResPath);
            GenerateReport.rfResProcessCallback("J1",
                    res2Database.getReportPath(),
                    res2Database.getResBookMap(),res2Database.getAbnormalBookNums());
            GenerateReport report = new GenerateReport();
            if (report.rfResFinished()) {
                report.generateReport();
                report.onReportEnd();
            }
            System.exit(0);
        }
    }
}
